// Copyright (C) 2010  Joan Puigcerver Perez, <joapuipe@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#ifndef __PEOPLE_HPP__
#define __PEOPLE_HPP__

#include <map>
#include <list>
#include <vector>
#include <string>

#include <Person.hpp>
#include <MapKey.hpp>
#include <MapNode.hpp>

/** File where people info is stored. */
#define PEOPLE_XML "xml/people.xml"
/** XML Schema used to check the format of PEOPLE_XML. */
#define PEOPLE_XSD "xml/people.xsd"

class Database;

/**
 * \class People
 *
 * This class is used to manage the set of persons in the database.
 * Each Person node is created dinamically and its address is stored
 * in a vector of pointers. In addition, it is also created a new node
 * in a map. This map is used to find the association name-person in O(log n).
 * Movies class has a similar behaviour.
 * \see Movies
 */
class People {
private:
  typedef std::pair<MapKey,MapNode> mapPair;
  typedef std::map<MapKey,MapNode>::iterator mapIterator;
  typedef std::vector<mapPair>::iterator vectIterator;

  /** This stores pointers to Person nodes. */
  std::vector<Person*> people;
  /** 
   * This associates each name with its Person. Used just while
   * the persons set is being loaded.
   */
  std::map<MapKey,MapNode> people_map;
  /** 
   * This associates each name with its Person. Used to support
   * fuzzy search.
   */  
  std::vector<mapPair> people_names;

  /**
   * Function used create and to add a new Person into de database. 
   * This function can't be used publicly. Use load() instead.
   * @see load
   */  
  Person * add_person(const std::string& name);
  /** 
   * Function used to add a new aka name to a given Person (as a pointer). 
   * This function can't be used publicly. Use load() instead.
   * @see load
   */
  void add_aka(const std::string& aka, Person* person);

public:
  /**
   * Destructor. Deletes all the created Person objects.
   */
  ~People();

  /**
   * This method is used to load a people XML file into a desired database.
   * It was necessary to pass a Database object because the links between
   * movies and persons are created at this time.
   */
  bool load(Database * database);

  /**
   * This function basically performs a binary search within among the persons in the database.
   * If the exact name was found, then the first argument returned is true. Otherwise, false is returned.
   * If the exact name was found and it is the main name for some person, then just this person is returned
   * in the list. If the name is not the main name for any person, all the persons with that aka name are
   * returned.
   * If the exact name was not found, a list of persons with similar main names or aka names are returned.
   */
  std::pair< bool,std::list<const Person*> > search(const std::string& name) const;

  /** This returns the number of movies in the database. */
  size_t size(void) const;
  
  /** Operator used to return a movie given its identifier. */
  const Person* operator [] (size_t i) const { return people[i]; }
  
  friend class SAXPeopleHandler;
  friend class Database;
};

#endif
